﻿using System;
using System.ComponentModel;

namespace Zive.Color {

    public enum HslChannels { H, S, L }

    public class HslColor: Color<HslColor, HslChannels> {

        public HslColor( ) { }

        public HslColor( Illuminants illuminant ) {
            _illuminant = illuminant;
        }

        public HslColor( double h, double s, double l ) {
            _h = h;
            _s = s;
            _l = l;
        }

        public HslColor( Illuminants illuminant, double h, double s, double l ) {
            _illuminant = illuminant;
            _h = h;
            _s = s;
            _l = l;
        }

        public HslColor( HslColor other ) {
            _illuminant = other._illuminant;
            _h = other._h;
            _s = other._s;
            _l = other._l;
        }

        public override HslColor Clone( ) {
            return new HslColor( this );
        }

        private Illuminants _illuminant = Illuminants.D65;
        /// <summary>Gets or sets the CIE standard illuminant and thus the white point.</summary>
        public override Illuminants Illuminant {
            get { return _illuminant; }
            set {
                _illuminant = value;
                OnPropertyChanged( "Illuminant" );
            }
        }

        private double _h;
        /// <summary>Gets or sets the value of the HSL hue angle channel of the color.</summary>
        public double H {
            get { return _h; }
            set {
                _h = value % 360.0;
                OnPropertyChanged( "H" );
            }
        }

        private double _s;
        /// <summary>Gets or sets the value of the HSL saturation channel of the color.</summary>
        public double S {
            get { return _s; }
            set {
                _s = value;
                OnPropertyChanged( "S" );
            }
        }

        private double _l;
        /// <summary>Gets or sets the value of the HSL lightness channel of the color.</summary>
        public double L {
            get { return _l; }
            set {
                _l = value;
                OnPropertyChanged( "L" );
            }
        }

        /// <summary>
        /// Gets or sets the value of a channel specified by its HslChannels enumeration member.
        /// </summary>
        public override double this[ HslChannels channel ] {
            get { return _getChannelFuncs[ (int) channel ]( this ); }
            set {
                _setChannelFuncs[ (int) channel ]( this, value );
                OnPropertyChanged( channel.ToString( ) );
            }
        }

        private static readonly Func<HslColor, double>[] _getChannelFuncs = {
            color => color._h,
            color => color._s,
            color => color._l,
        };

        private static readonly Action<HslColor, double>[ ] _setChannelFuncs = {
            ( color, value ) => { color.H = value; },
            ( color, value ) => { color.S = value; },
            ( color, value ) => { color.L = value; },
        };

        #region Object Members

        public override string ToString( ) {
            return string.Format( "H={0:N1}° S={1:N1} L={2:N1} illuminant={3:G}", _h, _s, _l, _illuminant );
        }

        #endregion

        #region INotifyPropertyChanged Members

        public override event PropertyChangedEventHandler PropertyChanged;

        protected override void OnPropertyChanged( string propertyName ) {
            var handlers = PropertyChanged;
            if ( null != handlers ) {
                handlers( this, new PropertyChangedEventArgs( propertyName ) );
            }
        }

        #endregion

    }

}
